﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using DNADataHiding.Model;
using DNADataHiding.Model.Encryption;
using DNADataHiding.Presenter.ViewContracts;
using DNADataHiding.Service;

namespace DNADataHiding.Presenter
{
    public class MainPresenter
    {
        private IMainView _view;
        private IDNASequenceService _sequenceService;

        public MainPresenter(IMainView view)
        {
            _view = view;
            _sequenceService = new DNASequenceService();
        }

        public void Init()
        {
            IDictionary<int, string> metodos = new Dictionary<int, string>()
                                                   {
                                                       { 1, "Insercion" },
                                                       { 2, "Substitucion" },
                                                       { 3, "Par Complementario"}
                                                   };

            this._view.PopularMetodosEncriptacion(metodos);
            this._view.PopularSecuenciasDeReferencia(_sequenceService.GetAllSequencesNames());
        }

        private IEncryptor GetEncryptor(int metodoEncriptacion, bool encrypt)
        {
            if (metodoEncriptacion == 1)
            {
                if (encrypt)
                {
                    int semillaMensaje, semillaSecuencia;

                    try
                    {
                        semillaMensaje = _view.SemillaMensaje;
                    }
                    catch (Exception E)
                    {
                        throw new Exception("Debe indicar un valor numerico para la semilla del mensaje");
                    }
                    
                    try
                    {
                        semillaSecuencia = _view.SemillaSecuencia;
                    }
                    catch (Exception E)
                    {
                        throw new Exception("Debe indicar un valor numerico para la semilla de la secuencia");
                    }

                    return new InsertionEncryptor(semillaMensaje, semillaSecuencia);
                }
                else
                {
                    int semillaMensaje, semillaSecuencia;

                    try
                    {
                        semillaMensaje = _view.SemillaMensajeParaDesencriptar;
                    }
                    catch (Exception E)
                    {
                        throw new Exception("Debe indicar un valor numerico para la semilla del mensaje");
                    }

                    try
                    {
                        semillaSecuencia = _view.SemillaSecuenciaParaDesencriptar;
                    }
                    catch (Exception E)
                    {
                        throw new Exception("Debe indicar un valor numerico para la semilla de la secuencia");
                    }

                    return new InsertionEncryptor(
                        _view.SemillaMensajeParaDesencriptar, _view.SemillaSecuenciaParaDesencriptar);
                }
            }
            else if (metodoEncriptacion == 2)
            {
                return new SubstitutionEncryptor();
            }
            else if (metodoEncriptacion == 3)
            {
                if (encrypt)
                {
                    return new ComplementaryPairEncryptor();
                }
                else
                {
                    int largoMayorParComplementario;

                    try
                    {
                        largoMayorParComplementario = _view.LargoMayorParComplementarioParaDesencriptar;
                    }
                    catch (Exception E)
                    {
                        throw new Exception("Debe indicar un valor numerico del largo mayor del par complementario");
                    }

                    return new ComplementaryPairEncryptor(largoMayorParComplementario);
                }
            }

            return null;
        }

        public void Encriptar()
        {
            DNASequence fakeSequence;
            IEncryptor encriptor;

            try
            {
                encriptor = GetEncryptor(_view.MetodoEncriptacion, true);

                DNASequence referenceSequence = _sequenceService.GetSequenceByName(this._view.Secuencia);
                
                if (string.IsNullOrEmpty(_view.Mensaje))
                {
                    _view.MostrarMensajeError("Debe ingresar una cadena para encriptar");
                    return;
                }

                fakeSequence = encriptor.Encrypt(this._view.Mensaje, referenceSequence);
            }
            catch (Exception E)
            {
                _view.MostrarMensajeError(E.Message);

                return;
            }

            this._view.Resultado = fakeSequence.ToString();

             if (_view.MetodoEncriptacion == 3)
             {
                 _view.LargoMayorParComplementario = encriptor.ExtraEncryptionOutput;
             }
        }

        private IList<DNASequence> GetRandomListOfSequences()
        {
            IList<DNASequence> retList = new List<DNASequence>();

            IList<string> sequencesNames = _sequenceService.GetAllSequencesNames();

            Random rnd = new Random();
            
            int randomSequencesCount = rnd.Next(1, sequencesNames.Count);

            for (int i = 0; i < randomSequencesCount; i++)
            {
                retList.Add(_sequenceService.GetSequenceByName(sequencesNames[rnd.Next(0, sequencesNames.Count)]));
            }
            
            return retList;
        }

        public void Desencriptar()
        {
            IEncryptor encryptor;

            try
            {
                encryptor = GetEncryptor(_view.MetodoDesencriptacion, false);

                if (string.IsNullOrEmpty(_view.SecuenciaFalsaParaDesencriptar))
                {
                    throw new Exception("Debe ingresar una secuencia falsa para desencriptar");
                }

                DNASequence referenceSequence =
                    _sequenceService.GetSequenceByName(this._view.SecuenciaReferenciaParaDesencriptar);
                DNASequence fakeSequence = new DNASequence(_view.SecuenciaFalsaParaDesencriptar);
                IList<DNASequence> randomListOfSequences;

                if (encryptor.NeedsRandomListOfSequences())
                {
                    randomListOfSequences = GetRandomListOfSequences();

                    int fakeSequenceposition = randomListOfSequences.Count / 2;

                    randomListOfSequences.Insert(fakeSequenceposition, fakeSequence);
                }
                else
                {
                    randomListOfSequences = new List<DNASequence>();
                    randomListOfSequences.Add(fakeSequence);
                }

                _view.MensajeDesencriptado = encryptor.Decrypt(randomListOfSequences, referenceSequence);
            }
            catch (Exception E)
            {
                _view.MostrarMensajeError(E.Message);
            }
        }
    }
}
